79. 热交换

79.1 重新加载静态内容

Spring Boot有很多用于热加载的选项,不过推荐使用spring-boot-devtools,因为它提供了其他开发时特性,比如快速应用重启和LiveReload,还有开发时敏感的配置加载(比如,模板缓存)。

此外,使用IDE开发也是一个不错的方式,特别是需要调试的时候(所有的现代IDEs都允许重新加载静态资源,通常也支持对变更的Java类进行热交换)。

最后,Maven和Gradle插件也支持命令行下的静态文件热加载。如果你使用其他高级工具编写css/js,并使用外部的css/js编译器,那你就可以充分利用该功能。

79.2. 在不重启容器的情况下重新加载模板

Spring Boot支持的大多数模板技术包含一个禁用缓存的配置选项,如果你正在使用spring-boot-devtools模块,Spring Boot在开发期间会自动为你配置那些属性

79.2.1 Thymeleaf模板

如果你正在使用Thymeleaf,那就将spring.thymeleaf.cache设置为false,查看ThymeleafAutoConfiguration可以获取其他Thymeleaf自定义选项。

79.2.2 FreeMarker模板

如果你正在使用FreeMarker,那就将spring.freemarker.cache设置为false,查看FreeMarkerAutoConfiguration 可以获取其他FreeMarker自定义选项。

79.2.3 Groovy模板

如果你正在使用Groovy模板,那就将spring.groovy.template.cache设置为false,查看GroovyTemplateAutoConfiguration可以获取其他Groovy自定义选项。

79.2.4 Velocity模板

如果你正在使用Velocity,那就将spring.velocity.cache设置为false,查看VelocityAutoConfiguration可以获取其他Velocity自定义选项。

79.3 应用快速重启

spring-boot-devtools模块包括应用自动重启支持,虽然没有其他技术快,比如JRebelSpring Loaded,但比"冷启动"快。在研究其他复杂重启选项时,你最好自己先试下,更多详情可参考Chapter 20, Developer tools章节。

79.4 在不重启容器的情况下重新加载Java类

现代IDEs(Eclipse, IDEA等)都支持字节码的热交换,所以如果你做了一个没有影响类或方法签名的改变,它会利索地重新加载并没有任何影响。

Spring Loaded在这方面走的更远,它能够重新加载方法签名改变的类定义,如果对它进行一些自定义配置可以强制ApplicationContext刷新自己(但没有通用的机制来确保这对一个运行中的应用总是安全的,所以它可能只是一个开发时的技巧)。

79.4.1 使用Maven配置Spring Loaded

为了在Maven命令行下使用Spring Loaded,你只需将它作为依赖添加到Spring Boot插件声明中即可,比如:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
            <version>1.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</plugin>

正常情况下,这在Eclipse和IntelliJ IDEA中工作的相当漂亮,只要它们有相应的,和Maven默认一致的构建配置(Eclipse m2e对此支持的更好,开箱即用)。

79.4.2 使用Gradle和IntelliJ IDEA配置Spring Loaded

如果想将Spring Loaded和Gradle,IntelliJ IDEA结合起来,那你需要付出代价。默认情况下,IntelliJ IDEA将类编译到一个跟Gradle不同的位置,这会导致Spring Loaded监控失败。

为了正确配置IntelliJ IDEA,你可以使用idea Gradle插件:

buildscript {
    repositories { jcenter() }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE"
        classpath 'org.springframework:springloaded:1.2.0.RELEASE'
    }
}

apply plugin: 'idea'

idea {
    module {
        inheritOutputDirs = false
        outputDir = file("$buildDir/classes/main/")
    }
}

// ...

IntelliJ IDEA必须配置跟命令行Gradle任务相同的Java版本,并且springloaded必须作为一个buildscript依赖被包含进去。

此外,你也可以启用Intellij IDEA内部的Make Project Automatically,这样不管什么时候只要文件被保存都会自动编译。